<!-- 封装echarts项目，可以随父元素大小变化而变化 -->
<template>
  <div class="chart">
    <div ref="chartRef" class="e-chart" v-if="!empty"></div>
    <div class="loading flex justify-content-center align-items-center" v-if="empty">
      {{ text }}
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
import * as echarts from 'echarts';
import type { ECharts, EChartsOption } from 'echarts';

/**
 * 创建图表
 *  chartInstance.setOption(options, notMerge, lazyUpdate);
 *  notMerge的值为true时，options会替换掉之前的配置项，否则，options会与当前的配置项进行合并。
 *  lazyUpdate的值为true时，options不会立即更新，而是等待下一个事件循环周期再更新(频繁调用时优化性能)。
 */

const props = defineProps({
  options: {
    type: Object as PropType<EChartsOption>,
    required: true, // 改为必填，因为v-if已经处理了空值情况
    default: () => ({}),
  },
  text: {
    type: String,
    default: '暂无数据',
  },
  empty: {
    type: Boolean,
    default: false,
  },
});

const chartRef = ref<HTMLElement | null>(null);
let chartInstance: ECharts | null = null;
let resizeObserver: ResizeObserver | null = null; // 提升到组件作用域

// 初始化图表
const initChart = async () => {
  if (!chartRef.value) return;

  // 清空容器
  chartRef.value.innerHTML = '';

  // 销毁旧实例和观察者
  chartInstance?.dispose();
  resizeObserver?.disconnect();

  try {
    await nextTick(); // 确保DOM更新完成

    // 创建新实例
    chartInstance = echarts.init(chartRef.value);

    // 设置选项
    if (props.options && Object.keys(props.options).length > 0) {
      chartInstance.setOption(props.options);
    }

    // 设置ResizeObserver
    resizeObserver = new ResizeObserver(() => {
      chartInstance?.resize();
    });
    resizeObserver.observe(chartRef.value);
  } catch (error) {
    console.error('ECharts init error:', error);
  }
};

// 清理资源
const cleanup = () => {
  resizeObserver?.disconnect();
  chartInstance?.dispose();
  chartInstance = null;
  resizeObserver = null;
};

// 监听options变化
watch(
  () => props.options,
  newOptions => {
    if (!chartInstance) {
      initChart();
    } else if (newOptions && Object.keys(newOptions).length > 0) {
      chartInstance.setOption(newOptions);
    }
  },
  { deep: true }
);

// 组件挂载后初始化
onMounted(() => {
  if (props.options && Object.keys(props.options).length > 0) {
    initChart();
  }
});

// 组件卸载前销毁实例
onBeforeUnmount(() => {
  cleanup();
});

// 暴露方法给父组件
defineExpose({
  getInstance: () => chartInstance,
  resize: () => chartInstance?.resize(),
});
</script>

<style lang="scss" scoped>
@import '@/style/common.scss';

.chart {
  width: 100%;
  height: 100%;
  position: relative;

  .e-chart {
    width: 100%;
    height: 100%;
  }

  .loading {
    width: 100%;
    height: 100%;
    font-weight: bold;
    font-size: 24px;
    letter-spacing: 2px;
  }
}
</style>
